import os
import shutil
import sys
import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QListWidget, QLabel,
                             QPushButton, QVBoxLayout, QHBoxLayout,
                             QMessageBox, QInputDialog, QMenu, QAction, QProgressDialog, QDesktopWidget, QSizePolicy)
from PyQt5.QtCore import Qt, pyqtSignal, QThread
from PyQt5.QtGui import QFont, QIcon


class BackupThread(QThread):
	progress = pyqtSignal(int, str)
	finished = pyqtSignal(bool, str)

	def __init__(self, src, dst, parent=None):
		super().__init__(parent)
		self.src = src
		self.dst = dst
		self._is_running = True

	def run(self):
		try:
			total_files = sum(len(files) for _, _, files in os.walk(self.src))
			copied_files = 0

			for root, dirs, files in os.walk(self.src):
				if not self._is_running:
					break

				rel_path = os.path.relpath(root, self.src)
				dest_dir = os.path.join(self.dst, rel_path)
				os.makedirs(dest_dir, exist_ok=True)

				for file in files:
					if not self._is_running:
						break

					src_file = os.path.join(root, file)
					dst_file = os.path.join(dest_dir, file)

					if file.lower().endswith('.sl2'):
						shutil.copy2(src_file, dst_file)
						copied_files += 1
						self.progress.emit(
							int((copied_files / total_files) * 100),
							f"正在备份: {file}"
						)

			if self._is_running:
				self.finished.emit(True, "备份完成")
			else:
				self.finished.emit(False, "操作已取消")

		except Exception as e:
			self.finished.emit(False, str(e))

	def stop(self):
		self._is_running = False


class ArchiveManager(QMainWindow):
	def __init__(self):
		super().__init__()
		self.setWindowTitle("多项目存档管理器")
		self.setGeometry(100, 100, 1000, 600)
		self.center()


		# 初始化属性
		self.backup_base_dir = r"D:\GameSaves"
		self.projects = {
			"黑暗之魂1重制版": os.path.expandvars(r"%USERPROFILE%\Documents\NBGI\DARK SOULS REMASTERED"),
			"黑暗之魂2": os.path.expandvars(r"%USERPROFILE%\AppData\Roaming\DarkSoulsII"),
			"黑暗之魂3": os.path.expandvars(r"%USERPROFILE%\AppData\Roaming\DarkSoulsIII"),
			"只狼":os.path.expandvars(r"%USERPROFILE%\AppData/Roaming/Sekiro"),
			"艾尔登法环": os.path.expandvars(r"%USERPROFILE%\AppData\Roaming\EldenRing")
		}
		self.current_project = ""

		# 初始化UI
		self.setup_ui()
		self.setup_menu()
		self.setup_styles()

		self.page_size = 20
		self.current_page = 0
		self.total_archives = 0

	def center(self):
		screen = QDesktopWidget().screenGeometry()
		size = self.geometry()
		self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)

	def setup_ui(self):
		main_widget = QWidget()
		self.setCentralWidget(main_widget)

		layout = QHBoxLayout(main_widget)

		# 左侧存档列表
		self.list_widget = QListWidget()
		self.list_widget.setSelectionMode(QListWidget.ExtendedSelection)
		self.list_widget.setContextMenuPolicy(Qt.CustomContextMenu)
		self.list_widget.customContextMenuRequested.connect(self.show_context_menu)
		layout.addWidget(self.list_widget, 3)

		# 右侧操作面板
		btn_layout = QVBoxLayout()
		self.btn_new = QPushButton("新建存档")
		self.btn_restore = QPushButton("恢复存档")
		self.btn_rename = QPushButton("重命名")
		self.btn_delete = QPushButton("删除")

		# 设置按钮ID
		self.btn_new.setObjectName("btn_new")
		self.btn_restore.setObjectName("btn_restore")
		self.btn_rename.setObjectName("btn_rename")
		self.btn_delete.setObjectName("btn_delete")

		for btn in [self.btn_new, self.btn_restore, self.btn_rename, self.btn_delete]:
			btn.setCursor(Qt.PointingHandCursor)
			btn_layout.addWidget(btn)

		btn_layout.addStretch()
		layout.addLayout(btn_layout, 1)

		# 连接信号
		self.btn_new.clicked.connect(self.create_archive)
		self.btn_restore.clicked.connect(self.restore_archive)
		self.btn_rename.clicked.connect(self.rename_archive)
		self.btn_delete.clicked.connect(self.delete_archive)

		# 状态栏
		self.status_bar = self.statusBar()
		self.status_bar.setFont(QFont("KaiTi", 20))

	def setup_menu(self):
		menubar = self.menuBar()

		# 创建项目菜单
		project_menu = menubar.addMenu("项目")


		for name in self.projects:
			action = QAction(name, self)
			action.triggered.connect(lambda checked, n=name: self.select_project(n))
			project_menu.addAction(action)

		# 帮助菜单
		help_menu = menubar.addMenu("帮助")
		about_action = QAction("关于", self)
		about_action.triggered.connect(self.show_about)
		help_menu.addAction(about_action)

	def setup_styles(self):
		self.setStyleSheet("""
			/* 菜单栏整体设置 */
	        QMenuBar {
	            font-size: 40px;
	            font-family: KaiTi;
	        }
	        
	        /* 下拉菜单项设置 */
	        QMenu::item {
	            font-size: 25;
	            padding: 6px 24px;
	        }
	        
	        /* 菜单标题设置 */
	        QMenu {
	            font-size: 40;
	        }
            QMainWindow {
                background-color: #F5F5F5;
            }
            QListWidget {
                background: white;
                border: 1px solid #E0E0E0;
                font-size: 30px;
                padding: 5px;
            }
            QPushButton {
                min-width: 100px;
                min-height: 32px;
                padding: 6px 12px;
                font-size: 20px;
                background: #FFFFFF;
                border: 1px solid #D9D9D9;
                color: #333333;
                margin: 3px;
            }
            QPushButton:hover {
                background: #F5F5F5;
                border-color: #409EFF;
            }
            QPushButton:pressed {
                background: #EBEBEB;
            }
            QPushButton#btn_delete {
                color: #FF4444;
                border-color: #FFA39E;
            }
            QPushButton#btn_delete:hover {
                background: #FFF1F0;
            }
            QPushButton#btn_delete:pressed {
                background: #FFCCC7;
            }
            QMenu {
                background: white;
                border: 1px solid #E8E8E8;
                padding: 8px;
            }
            QMenu::item {
                padding: 6px 24px;
                font-size: 35px;
            }
            /* 仅作用于主窗口的菜单 */
			QMainWindow QMenu::item:selected {
			    background: #F5F5F5;
			    font-size: 38px;
			}
            
            
            QInputDialog QLabel {
		        font-size: 30px;  /* 设置对话框标签字体大小 */
		        font-family: "Microsoft YaHei";  /* 可选：统一字体 */
		    }
		    QInputDialog QLineEdit {
		        font-size: 25px;  /* 可选：同步调整输入框字体 */
		        min-height: 40px;  /* 可选：调整输入框高度 */
		    }
		    

		    QMessageBox {
		        background-color: #ffffff;  /* 背景色 */
		        font-size: 25px;           /* 字体大小 */
		    }
		    QMessageBox QLabel#qt_msgbox_label {  /* 文本标签 */
		        color: #D84315;           /* 文字颜色 */
		        min-width: 300px;         /* 最小宽度 */
		    }
		    QMessageBox QPushButton {     /* 按钮样式 */
		        background-color: #f8f9f9;
		        color: red;
		        border: none;
		        padding: 5px 10px;
		    }
		    /* 精准定位QMessageBox中的按钮 */
			QMessageBox QPushButton:hover {
			    font-weight: bold;  /* 悬停时加粗 */
			    background: #fcf3cf;  /* 透明背景 */
			}
        """)

	def show_context_menu(self, pos):
		menu = QMenu()
		selected_items = self.list_widget.selectedItems()

		if selected_items:
			menu.addAction("重命名", self.rename_archive)
			menu.addAction("删除", self.delete_archive)
			menu.addSeparator()

		menu.addAction("新建存档", self.create_archive)
		menu.addAction("恢复存档", self.restore_archive)
		menu.exec_(self.list_widget.mapToGlobal(pos))

	def select_project(self, name):
		self.current_project = name
		if not hasattr(self, 'project_label'):
			self.project_label = QLabel(f"当前项目: {name}")
			self.project_label.setFont(QFont("KaiTi", 20))
			self.project_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
			self.project_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
			self.status_bar.addPermanentWidget(self.project_label, stretch=1)  # 强制左对齐布局
		else:
			self.project_label.setText(f"当前项目: {name}")
		self.load_archives()

	def load_archives(self):
		self.list_widget.clear()
		project_dir = os.path.join(self.backup_base_dir, self.current_project)

		try:
			# 新增目录创建逻辑
			os.makedirs(project_dir, exist_ok=True)

			all_archives = []
			for dir_name in os.listdir(project_dir):
				dir_path = os.path.join(project_dir, dir_name)
				if os.path.isdir(dir_path):
					all_archives.append(dir_name)

			# 按修改时间排序
			all_archives.sort(
				key=lambda x: os.path.getmtime(os.path.join(project_dir, x)),
				reverse=True
			)
			self.total_archives = len(all_archives)

			start = self.current_page * self.page_size
			end = start + self.page_size
			current_page_archives = all_archives[start:end]

			self.list_widget.addItems(current_page_archives)

			if self.total_archives > self.page_size:
				self.list_widget.addItem(
					f"--- 已加载 {(self.current_page + 1) * self.page_size} / {self.total_archives} ---")

		except Exception as e:
			QMessageBox.critical(self, "错误", f"目录访问失败: {str(e)}")
	def validate_filename(self, name):
		illegal_chars = r'\/:*?"<>|'
		if any(c in name for c in illegal_chars):
			return False, "包含非法字符: \\/:*?\"<>|"

		try:
			if len(name.encode('utf-8')) > 220:
				return False, "名称过长（最多110个汉字）"
		except UnicodeEncodeError:
			return False, "包含不支持的字符"

		return True, ""

	def has_sl2_files(self,directory):
		"""检查目录及其子目录中是否存在.sl2文件"""
		for root, _, files in os.walk(directory):
			if any(file.lower().endswith('.sl2') for file in files):
				return True
		return False

	def create_archive(self):
		# # 临时设置样式
		# style = """
		#     QLineEdit {
		#         font-size: 30px;
		#         min-height: 40px;
		#         padding: 8px;
		#     }
		#     QInputDialog QLabel {  /* 对话框标签 */
		# 	    font-size: 30px;
		# 	}
		# 	QInputDialog QPushButton {  /* 对话框按钮 */
		# 	    min-width: 80px;
		# 	    min-height: 30px;
		# 	}
		# """
		#
		# QApplication.instance().setStyleSheet(style)  # 应用临时样式
		if not self.current_project:
			QMessageBox.warning(self, "警告", "请先选择项目")
			return

		source_dir = self.get_save_source_path()
		if not source_dir:
			return
		if not self.has_sl2_files(source_dir):
			QMessageBox.critical(self, "错误", "存档目录中未找到.sl2文件，无法创建备份")
			return
		name, ok = QInputDialog.getText(
			self, "新建存档",
			"输入存档名称（支持中文）:\n示例: 通关存档_最终BOSS",
			text="存档_" + datetime.datetime.now().strftime("%Y%m%d")
		)
		if not ok or not name:
			return

		is_valid, msg = self.validate_filename(name)
		if not is_valid:
			QMessageBox.critical(self, "错误", f"无效名称: {msg}")
			return

		timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
		target_dir = os.path.join(
			self.backup_base_dir,
			self.current_project,
			f"{timestamp}_{name}"
		)

		# 检查磁盘空间
		try:
			total, used, free = shutil.disk_usage(os.path.split(target_dir)[0])
			source_size = sum(os.path.getsize(os.path.join(root, f))
			                  for root, _, files in os.walk(source_dir)
			                  for f in files)
			if free < source_size * 1.2:
				raise Exception(f"需要至少 {source_size // 1024 // 1024}MB 剩余空间")
		except Exception as e:
			QMessageBox.critical(self, "错误", f"空间不足: {str(e)}")
			return

		# 启动异步备份
		self.backup_thread = BackupThread(source_dir, target_dir)
		self.backup_thread.progress.connect(self.update_progress)
		self.backup_thread.finished.connect(self.handle_backup_result)
		self.backup_thread.start()

		# 显示进度对话框
		self.progress_dialog = QProgressDialog("正在备份存档...", "取消", 0, 100, self)
		self.progress_dialog.canceled.connect(self.backup_thread.stop)
		self.progress_dialog.setWindowModality(Qt.WindowModal)
		self.progress_dialog.show()

	def update_progress(self, value, message):
		self.progress_dialog.setValue(value)
		# self.status_bar.showMessage(message)

	def handle_backup_result(self, success, message):
		self.progress_dialog.close()
		if success:
			QMessageBox.information(self, "成功", "存档创建成功")
			self.load_archives()
		else:
			QMessageBox.critical(self, "错误", message)

	def restore_archive(self):
		selected_items = self.list_widget.selectedItems()
		if not selected_items:
			QMessageBox.warning(self, "警告", "请选择要恢复的存档")
			return

		reply = QMessageBox.question(
			self, "确认",
			f"确定要恢复 {len(selected_items)} 个存档吗？\n当前存档将被覆盖！",
			QMessageBox.Yes | QMessageBox.No
		)
		if reply == QMessageBox.No:
			return

		# 批量恢复处理
		progress = QProgressDialog("正在恢复存档...", "取消", 0, len(selected_items), self)
		progress.setWindowModality(Qt.WindowModal)

		for i, item in enumerate(selected_items):
			if progress.wasCanceled():
				break
			progress.setValue(i + 1)
			progress.setLabelText(f"正在恢复: {item.text()}")

			source_dir = os.path.join(self.backup_base_dir, self.current_project, item.text())
			target_dir = self.get_save_source_path()

			try:
				# 清空目标目录
				for root, _, files in os.walk(target_dir):
					for file in files:
						if file.lower().endswith('.sl2'):
							os.remove(os.path.join(root, file))

				# 复制文件
				shutil.copytree(source_dir, target_dir, dirs_exist_ok=True)

			except Exception as e:
				QMessageBox.critical(self, "错误", f"恢复失败: {str(e)}")
				return

		QMessageBox.information(self, "成功", f"已恢复 {len(selected_items)} 个存档")

	def rename_archive(self):
		selected = self.list_widget.currentItem()
		if not selected:
			QMessageBox.warning(self, "警告", "请选择要重命名的存档")
			return

		old_name = selected.text()
		new_name, ok = QInputDialog.getText(
			self, "重命名",
			"输入新名称:",
			text=old_name.split('_', 1)[-1]
		)
		if not ok or not new_name:
			return

		is_valid, msg = self.validate_filename(new_name)
		if not is_valid:
			QMessageBox.critical(self, "错误", f"无效名称: {msg}")
			return

		old_path = os.path.join(self.backup_base_dir, self.current_project, old_name)
		new_path = os.path.join(self.backup_base_dir, self.current_project, new_name)

		try:
			os.rename(old_path, new_path)
			self.load_archives()
			QMessageBox.information(self, "成功", "重命名完成")
		except Exception as e:
			QMessageBox.critical(self, "错误", f"重命名失败: {str(e)}")

	def delete_archive(self):
		selected_items = self.list_widget.selectedItems()
		if not selected_items:
			QMessageBox.warning(self, "警告", "请选择要删除的存档")
			return

		# 增强删除确认对话框
		msg = QMessageBox(self)
		msg.setIcon(QMessageBox.Warning)
		msg.setWindowTitle("确认删除")
		msg.setText(f"即将永久删除 {len(selected_items)} 个存档！\n此操作不可恢复！")
		msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
		msg.button(QMessageBox.Yes).setText("确认删除")
		msg.button(QMessageBox.No).setText("取消操作")

		if msg.exec_() == QMessageBox.No:
			return

		progress = QProgressDialog("正在删除...", "取消", 0, len(selected_items), self)
		progress.setWindowModality(Qt.WindowModal)

		for i, item in enumerate(selected_items):
			if progress.wasCanceled():
				break
			progress.setValue(i + 1)
			dir_path = os.path.join(self.backup_base_dir, self.current_project, item.text())
			try:
				shutil.rmtree(dir_path)
			except Exception as e:
				QMessageBox.critical(self, "错误", f"删除失败: {str(e)}")
				return

		self.load_archives()
		QMessageBox.information(self, "成功", "删除操作完成")

	def get_save_source_path(self):
		base_path = self.projects.get(self.current_project)
		if not base_path or not os.path.exists(base_path):
			QMessageBox.critical(self, "错误", "存档路径不存在")
			return None

		subdirs = [d for d in os.listdir(base_path)
		           if os.path.isdir(os.path.join(base_path, d))]

		if len(subdirs) != 1:
			QMessageBox.critical(self, "错误", "存档目录结构异常")
			return None

		return os.path.join(base_path, subdirs[0])

	def show_about(self):
		about_text ="""
		<b>游戏存档管理器 v2.1</b><br><br>
		    支持功能：<br>
		    - 多项目管理<br>
		    - 存档备份/恢复<br>
		    - 批量操作支持<br><br>
		    开发者：deepseek<br>
		    最后更新：2025-04-26
		    """

		msg_box = QMessageBox()
		msg_box.setWindowTitle("关于")
		msg_box.setText(about_text)
		msg_box.setMinimumSize(500, 300)  # 关键：设置最小宽度和高度
		msg_box.exec_()


if __name__ == "__main__":
	app = QApplication(sys.argv)
	app.setWindowIcon(QIcon("icon.ico"))
	window = ArchiveManager()
	window.show()
	sys.exit(app.exec_())